package com.polaris.live.im.manager

import androidx.lifecycle.LifecycleOwner
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.im.sfs.LIVE_INVITE_CALL
import com.polaris.live.im.sfs.LIVE_INVITE_FOLLOW
import com.polaris.live.im.sfs.LIVE_INVITE_GIFT
import com.polaris.live.im.sfs.LIVE_NEW_FOLLOWER
import com.polaris.live.im.sfs.LIVE_PROMPT
import com.polaris.live.im.sfs.LIVE_PUBLIC_SCREEN
import com.polaris.live.im.sfs.LIVE_RECOMMEND_CARD
import com.polaris.live.im.sfs.LIVE_SEND_GIFT
import com.polaris.live.im.sfs.LIVE_UP_SEAT_INVITE
import com.polaris.live.im.sfs.LUCKY_BACKPACK_GIFT
import com.polaris.live.im.sfs.bean.live.AbstractLiveMessage
import com.polaris.live.im.sfs.bean.live.SendLiveMessage
import com.polaris.live.im.sfs.core.bean.AbstractMessage
import com.polaris.live.im.sfs.core.bean.DataArgument
import com.polaris.live.im.sfs.core.bean.getRoomId
import com.polaris.live.im.sfs.processor.impl.LiveEventMessageProcessor
import com.polaris.live.im.utils.PublicMessageUtils
import com.polaris.live.utils.LifecycleListenerDispatcher
import com.polaris.live.utils.MapLifecycleListener
import com.polaris.live.utils.MapLifecycleListenerDispatcher
import kotlinx.coroutines.withContext
import sfs2x.client.entities.variables.RoomVariable
import sfs2x.client.entities.variables.SFSRoomVariable
import kotlin.reflect.KClass

/**
 * ImLiveManager
 *
 * @author Created by lucas on 2023/11/10 09:54
 */
object ImLiveManager {

    //公屏的消息类型
    val publicTypes = setOf(
        LIVE_PUBLIC_SCREEN,
        LIVE_PROMPT,
        LIVE_SEND_GIFT,
        LIVE_INVITE_FOLLOW,
        LIVE_INVITE_GIFT,
        LIVE_INVITE_CALL,
        LIVE_NEW_FOLLOWER,
        LIVE_UP_SEAT_INVITE,
        LUCKY_BACKPACK_GIFT,
        LIVE_RECOMMEND_CARD
    )

    private val liveMessageDispatcher =
        MapLifecycleListenerDispatcher<LiveCommandWrapper<out AbstractMessage>>("liveMessageDispatcher")
    private val liveEventDispatcher =
        LifecycleListenerDispatcher<OnLiveEventListener>("liveEventDispatcher")
    private val livePublicMessageDispatcher =
        LifecycleListenerDispatcher<LiveWrapper<OnLivePublicMessageListener>>("livePublicMessageDispatcher")
    private val liveVariablesUpdateDispatcher =
        LifecycleListenerDispatcher<LiveWrapper<OnLiveVariablesUpdateListener>>("liveVariablesUpdateDispatcher")
    private val liveUserCountChangeDispatcher =
        LifecycleListenerDispatcher<LiveWrapper<OnLiveUserCountChangeListener>>("liveUserCountChangeDispatcher")

    /**
     * 监听消息，需要先加入到[LiveEventMessageProcessor.commands]中
     */
    fun observe(
        owner: LifecycleOwner,
        observerListener: OnLiveObserveListener,
        build: LiveMessageBuilder.() -> Unit,
    ) {
        build(LiveMessageBuilder(owner, observerListener))
    }

    class LiveMessageBuilder(
        private val owner: LifecycleOwner,
        private val observerListener: OnLiveObserveListener,
    ) {

        inline fun <reified T : AbstractMessage> withMessage(
            command: String,
            l: OnLiveMessageListener<T>,
        ) {
            withMessage(command, T::class, l)
        }

        fun <T : AbstractMessage> withMessage(
            command: String,
            type: KClass<T>,
            l: OnLiveMessageListener<T>,
        ) {
            observe(owner, command, type, observerListener, l)
        }
    }

    /**
     * 监听消息，需要先加入到[LiveEventMessageProcessor.commands]中
     */
    inline fun <reified T : AbstractMessage> observe(
        owner: LifecycleOwner,
        command: String,
        observerListener: OnLiveObserveListener,
        l: OnLiveMessageListener<T>,
    ) {
        observe(owner, command, T::class, observerListener, l)
    }

    /**
     * 监听消息，需要先加入到[LiveEventMessageProcessor.commands]中
     */
    fun <T : AbstractMessage> observe(
        owner: LifecycleOwner,
        command: String,
        type: KClass<T>,
        observerListener: OnLiveObserveListener,
        l: OnLiveMessageListener<T>,
    ) {
        if (command !in LiveEventMessageProcessor.commands) {
            throw IllegalArgumentException("The command to be listened to must be registered in the LiveEventMessageProcessor first")
        }

        val wrapper = LiveCommandWrapper(
            command,
            observerListener,
            l,
            type
        )

        liveMessageDispatcher.observe(owner, wrapper)
    }

    /**
     * 添加直播事件监听，通过[observerListener]过滤
     */
    fun observeEvent(
        owner: LifecycleOwner,
        l: OnLiveEventListener,
    ) {
        liveEventDispatcher.observe(owner, l)
    }

    /**
     * 添加公屏消息监听，通过[observerListener]过滤
     */
    fun observePublicMessage(
        owner: LifecycleOwner,
        observerListener: OnLiveObserveListener,
        l: OnLivePublicMessageListener,
    ) {
        livePublicMessageDispatcher.observe(owner, LiveWrapper(observerListener, l))
    }

    /**
     * 监听room变量更新，通过[observerListener]过滤
     *
     * 注意：这里返回的需要是anchorId，用于减少消耗
     */
    fun observeVariableUpdate(
        owner: LifecycleOwner,
        observerListener: OnLiveObserveListener,
        l: OnLiveVariablesUpdateListener,
    ) {
        liveVariablesUpdateDispatcher.observe(owner, LiveWrapper(observerListener, l))
    }

    /**
     * 监听房间人数改变，通过[observerListener]过滤
     *
     * 注意：这里返回的需要是anchorId，用于减少消耗
     */
    fun observeUserCountChange(
        owner: LifecycleOwner,
        observerListener: OnLiveObserveListener,
        l: OnLiveUserCountChangeListener,
    ) {
        liveUserCountChangeDispatcher.observe(owner, LiveWrapper(observerListener, l))
    }

    internal suspend fun onMessage(command: String, argument: DataArgument) {
        val listeners = liveMessageDispatcher.getListener(command)
        if (listeners.isEmpty()) {
            return
        }

        listeners.forEach {
            val data = try {
                argument.getData(it.type)
            } catch (t: Throwable) {
                t.printStackTrace()

                null
            }

            if (data != null) {
                withContext(CoroutineScopeManager.mainDispatcher) {
                    val liveId = it.observerListener.onObserveId()

                    //如果是AbstractLiveMessage需要比较直播间id
                    if (data is AbstractLiveMessage) {
                        if (liveId == OnLiveObserveListener.ANY_ID || (liveId != null && liveId == data.liveId)) {
                            (it.value as OnLiveMessageListener<AbstractMessage>).onMessage(data)
                        }
                    } else {
                        (it.value as OnLiveMessageListener<AbstractMessage>).onMessage(data)
                    }
                }
            }
        }
    }

    internal suspend fun onPublicMessage(liveMessage: SendLiveMessage) {
        withContext(CoroutineScopeManager.mainDispatcher) {
            livePublicMessageDispatcher.listeners.forEach {
                val liveId = it.observerListener.onObserveId()
                if (liveId != null && liveMessage.businessId == liveId) {
                    it.value.onMessage(liveMessage)
                    if (liveMessage.type in LiveEventMessageProcessor.publicMessages) {
                        PublicMessageUtils.onPublicMessage(liveMessage)
                    }
                }
            }
        }
    }

    internal suspend fun onVariableUpdate(argument: DataArgument) {
        val roomId = argument.getRoomId() ?: return
        val changeVariableNames = argument.arguments["changedVars"]
        if (changeVariableNames !is List<*>) {
            return
        }
        val variables = argument.getRoom()?.variables?.associateBy { it.name } ?: return

        val changeVariableSet = changeVariableNames.map { it.toString() }.toSet()

        withContext(CoroutineScopeManager.mainDispatcher) {
            liveVariablesUpdateDispatcher.listeners.forEach {
                val anchorId = it.observerListener.onObserveId()
                if (anchorId != null && roomId == anchorId) {
                    changeVariableSet.forEach { name ->
                        val variable = variables[name] ?: SFSRoomVariable(name, null)
                        it.value.onVariablesUpdate(variable)
                    }
                }
            }
        }
    }

    internal suspend fun onEvent(command: String, argument: DataArgument) {
        onUserCountChange(argument)

        withContext(CoroutineScopeManager.mainDispatcher) {
            liveEventDispatcher.listeners.forEach {
                it.onEvent(command, argument)
            }
        }
    }

    internal suspend fun onUserCountChange(argument: DataArgument) {
        val room = argument.getRoom() ?: return
        val roomId = room.getRoomId() ?: return

        withContext(CoroutineScopeManager.mainDispatcher) {
            liveUserCountChangeDispatcher.listeners.forEach {
                val anchorId = it.observerListener.onObserveId()
                if (anchorId != null && roomId == anchorId) {
                    it.value.onUserCountChange(room.userCount)
                }
            }
        }
    }
}

fun interface OnLiveObserveListener {

    fun onObserveId(): Long?

    companion object {

        const val ANY_ID = -1L

    }
}

fun interface OnLiveMessageListener<T : AbstractMessage> {

    fun onMessage(message: T)

}

fun interface OnLiveEventListener {

    fun onEvent(event: String, argument: DataArgument)

}

fun interface OnLivePublicMessageListener {

    fun onMessage(message: SendLiveMessage)

}

fun interface OnLiveVariablesUpdateListener {

    fun onVariablesUpdate(variable: RoomVariable)

}

fun interface OnLiveUserCountChangeListener {

    fun onUserCountChange(count: Int)

}

data class LiveWrapper<T>(
    val observerListener: OnLiveObserveListener,
    val value: T,
)

data class LiveCommandWrapper<T : AbstractMessage>(
    override val key: String,
    val observerListener: OnLiveObserveListener,
    val value: OnLiveMessageListener<T>,
    val type: KClass<T>,
) : MapLifecycleListener()